<template>
  <div class="player">
    <transition name="normal">
      <div class="normal-player" v-show="fullScreen">
        <template v-if="currentSong">
          <div class="background">
            <img :src="currentSong.pic" />
          </div>
          <div class="top">
            <div class="back" @click="goBack">
              <i class="icon-back"></i>
            </div>
            <h1 class="title">{{ currentSong.name }}</h1>
            <h2 class="subtitle">{{ currentSong.singer }}</h2>
          </div>
          <!--  唱片-->
          <div
            class="middle"
            @touchstart.prevent="onMiddleTouchStart"
            @touchmove.prevent="onMiddleTouchMove"
            @touchend.prevent="onMiddleTouchEnd"
          >
            <div class="middle-l" :style="middleLStyle">
              <div class="cd-wrapper" ref="cdRef">
                <img
                  class="image"
                  ref="cdImageRef"
                  :class="cdCls"
                  :src="currentSong.pic"
                />
              </div>
              <div class="playing-lyric-wrapper">
                <div class="playing-lyric">{{ playingLyric }}</div>
              </div>
            </div>
            <!--  lyric歌词-->
            <Scroll class="middle-r" ref="lyricScrollRef" :style="middleRStyle">
              <div class="lyric-wrapper">
                <div v-if="currentLyric" ref="lyricListRef">
                  <p
                    class="text"
                    :class="{ current: currentLineNum === index }"
                    v-for="(line, index) in currentLyric.lines"
                    :key="line.num"
                  >
                    {{ line.txt }}
                  </p>
                </div>
              </div>
            </Scroll>
          </div>
          <!--  播放控制区-->
          <div class="bottom">
            <div class="dot-wrapper">
              <span
                class="dot"
                :class="{ active: currentShow === 'cd' }"
              ></span>
              <span
                class="dot"
                :class="{ active: currentShow === 'lyric' }"
              ></span>
            </div>
            <!--  进度条-->
            <div class="progress-wrapper">
              <span class="time time-l">{{ formatTime(currentTime) }}</span>
              <div class="progress-bar-wrapper">
                <progress-bar
                  @progress-changing="onProgressChanging"
                  @progress-changed="onProgressChanged"
                  :progress="progress"
                ></progress-bar>
              </div>
              <span class="time time-r">{{
                formatTime(currentSong.duration)
              }}</span>
            </div>
            <div class="operators">
              <!--播放模式-->
              <div class="icon i-left">
                <i :class="modeIcon" @click="changeMode"></i>
              </div>
              <div class="icon i-left" :class="disableCls">
                <i class="icon-prev" @click="prev"></i>
              </div>
              <div class="icon i-center" :class="disableCls">
                <i :class="playIcon" @click="togglePlay"></i>
              </div>
              <div class="icon i-right" :class="disableCls">
                <i class="icon-next" @click="next"></i>
              </div>
              <div class="icon i-right">
                <i
                  :class="getFavoriteIcon(currentSong)"
                  @click="toggleFavorite(currentSong)"
                ></i>
              </div>
            </div>
          </div>
        </template>
      </div>
    </transition>
    <mini-player :progress="progress" :toggle-play="togglePlay"></mini-player>
    <audio
      ref="audioRef"
      @pause="pause"
      @canplay="ready"
      @error="error"
      @timeupdate="updateTime"
      @ended="end"
    ></audio>
  </div>
</template>
<script>
import { computed, ref, watch } from 'vue'
import { useStore } from 'vuex'
import { formatTime } from '@/assets/js/util'
import useMode from '@/components/player/use-mode'
import useFavorite from '@/components/player/use-favorite'
import { PLAY_MODE } from '@/assets/js/constant'
import useCd from '@/components/player/use-cd'
import useLyric from '@/components/player/use-lyric'
import progressBar from '@/components/player/progress-bar.vue'
import Scroll from '@/components/base/scroll/scroll.vue'
import useMiddleInteractive from '@/components/player/use-middle-interactive'
import MiniPlayer from '@/components/player/mini-player.vue'
export default {
  name: 'player',
  methods: { formatTime },
  components: {
    MiniPlayer,
    progressBar,
    Scroll
  },
  setup () {
    const store = useStore()
    const audioRef = ref()
    const songReady = ref(false)
    const currentTime = ref(0)
    let progressChanging = false

    const currentSong = computed(() => store.getters.currentSong)
    const fullScreen = computed(() => store.state.fullScreen)
    const playing = computed(() => store.state.playing)
    const playIcon = computed(() =>
      playing.value ? 'icon-pause' : 'icon-play'
    )
    const playlist = computed(() => store.state.playlist)
    const currentIndex = computed(() => store.state.currentIndex)
    const disableCls = computed(() => (songReady.value ? '' : 'disable'))
    const progress = computed(
      () => currentTime.value / currentSong.value.duration
    )
    const playMode = computed(() => store.state.playMode)

    // hooks
    const { modeIcon, changeMode } = useMode()
    const { getFavoriteIcon, toggleFavorite } = useFavorite()
    const { cdCls, cdRef, cdImageRef } = useCd()
    const {
      currentLyric,
      currentLineNum,
      lyricListRef,
      lyricScrollRef,
      playingLyric,
      playLyric,
      stopLyric
    } = useLyric({ songReady, currentTime })
    const {
      currentShow,
      middleLStyle,
      middleRStyle,
      onMiddleTouchStart,
      onMiddleTouchMove,
      onMiddleTouchEnd
    } = useMiddleInteractive()

    watch(currentSong, (newSong) => {
      // 重置歌曲时间
      currentTime.value = 0
      if (!newSong.id || !newSong.url) return
      // 歌曲发生变化
      songReady.value = false
      const audioEl = audioRef.value
      audioEl.src = newSong.url
      audioEl && audioEl.play()
    })
    watch(playing, (newPlaying) => {
      if (!songReady.value) return
      const audioEl = audioRef.value
      if (newPlaying) {
        console.log('watch playing!')
        audioEl.play()
        playLyric()
      } else {
        audioEl.pause()
        stopLyric()
      }
    })

    const goBack = () => {
      store.commit('setFullScreen', false)
    }
    const togglePlay = () => {
      store.commit('setPlayingState', !playing.value)
    }
    const pause = () => {
      console.log('pause event!')
      store.commit('setPlayingState', false)
    }

    // 如果 songReady 为 false，则直接返回，不允许切换歌曲,避免歌曲未加载完成报错
    const prev = () => {
      const list = playlist.value
      if (!songReady.value || !list.length) return
      if (list.length === 1) {
        loop()
      } else {
        let index = currentIndex.value - 1
        if (index === -1) {
          index = list.length - 1
        }
        store.commit('setCurrentIndex', index)
        if (!playing.value) {
          store.commit('setPlayingState', true)
        }
      }
    }
    const next = () => {
      const list = playlist.value
      if (!songReady.value || !list.length) return
      if (list.length === 1) {
        loop()
      } else {
        let index = currentIndex.value + 1
        if (index === list.length) {
          index = 0
        }
        store.commit('setCurrentIndex', index)
        if (!playing.value) {
          store.commit('setPlayingState', true)
        }
      }
    }
    const loop = () => {
      const audioEl = audioRef.value
      // 音频播放位置重置到开头
      audioEl.currentTime = 0
      // 歌曲播放结束，播放暂停，按钮暂停
      audioEl.play()
      store.commit('setPlayingState', true)
    }
    const ready = () => {
      console.log('player ready')
      if (songReady.value) return
      songReady.value = true
      // 首次点击歌曲播放不会触发watch playing，所以需要调用playLyric
      playLyric()
    }
    const error = () => {
      // 允许歌曲前进后退,不要卡在加载状态
      songReady.value = true
      console.log('player error')
    }
    /**
     * bug updateTime/onProgressChanging同时触发，会导致进度条出现跳跃
     * 手动拖拽和自动更新冲突
     */
    // 音频播放更新当前播放时间
    const updateTime = (e) => {
      // 手动拖拽时，不会更新时间
      if (!progressChanging) {
        currentTime.value = e.target.currentTime
      }
    }
    /**
     * 手动拖拽进度条
     */
    const onProgressChanging = (progress) => {
      progressChanging = true
    }
    const onProgressChanged = (progress) => {
      progressChanging = false
      audioRef.value.currentTime = currentTime.value =
        currentSong.value.duration * progress
      // 歌曲暂停时，拖动进度条，播放开启
      if (!playing.value) {
        store.commit('setPlayingState', true)
      }
      playLyric()
    }
    /**
     * 歌曲播放完毕处理
     * 此时开始判断播放模式
     * 1、单曲循环：重新播放
     * 2、顺序或随机播放：继续播放下一首
     */
    const end = () => {
      currentTime.value = 0
      if (playMode.value === PLAY_MODE.loop) {
        loop()
      } else {
        next()
      }
    }
    return {
      currentSong,
      fullScreen,
      playIcon,
      audioRef,
      disableCls,
      goBack,
      togglePlay,
      // 播放器播放处理
      pause,
      prev,
      next,
      ready,
      error,
      end,
      // mode
      modeIcon,
      changeMode,
      // favorite
      getFavoriteIcon,
      toggleFavorite,
      // progress
      progress,
      currentTime,
      updateTime,
      onProgressChanging,
      onProgressChanged,
      // cd唱片
      cdCls,
      cdRef,
      cdImageRef,
      // lyric歌词
      currentLyric,
      currentLineNum,
      lyricListRef,
      lyricScrollRef,
      playingLyric,
      // middle交互
      currentShow,
      middleLStyle,
      middleRStyle,
      onMiddleTouchStart,
      onMiddleTouchMove,
      onMiddleTouchEnd
    }
  }
}
</script>

<style lang="scss" scoped>
.player {
  .normal-player {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    z-index: 30;
    background: $color-background;
    .background {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      opacity: 0.6;
      filter: blur(20px);
      img {
        width: 100%;
        height: 100%;
      }
    }
    .top {
      position: relative;
      left: 50%;
      top: 0;
      transform: translateX(-50%);
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: 12px;
      width: 100%;
      .back {
        position: absolute;
        left: 16px;
        top: 0;
        .icon-back {
          display: block;
          transform: rotate(-90deg);
          padding: 10px;
          font-size: $font-size-large-x;
          color: $color-theme;
        }
      }
      .title {
        padding-bottom: 12px;
        font-size: $font-size-large;
      }
      .subtitle {
        font-size: $font-size-medium;
      }
    }
    .middle {
      position: fixed;
      top: 80px;
      bottom: 170px;
      width: 100%;
      display: flex;
      flex-wrap: nowrap;
      .middle-l {
        //某个 flex 子项占据整个容器的宽度，同时防止它在空间不足时被压缩或在有多余空间时扩展
        flex: 0 0 100%;
      }
      .cd-wrapper {
        display: flex;
        justify-content: center;
        align-items: center;
        .image {
          width: 300px;
          height: 300px;
          border-radius: 50%;
          box-sizing: border-box;
          border: 10px solid rgba(255, 255, 255, 0.1);
        }
        .playing {
          animation: rotate 20s linear infinite;
        }
      }
      .playing-lyric-wrapper {
        display: flex;
        justify-content: center;
        margin-top: 30px;
        color: $color-text-l;
        font-size: $font-size-medium;
      }
      .middle-r {
        flex: 0 0 100%;
        overflow: hidden;
        // 开始状态歌词列表位置
        transform: translateX(100%);
        .lyric-wrapper {
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          .text {
            line-height: 32px;
            text-align: center;
            color: $color-text-l;
            font-size: $font-size-medium;
            &.current {
              color: $color-text;
            }
          }
        }
      }
    }
    .bottom {
      position: absolute;
      bottom: 40px;
      left: 50%;
      transform: translateX(-50%);
      width: 100%;
      .progress-wrapper {
        display: flex;
        align-items: center;
        padding: 10px 40px;
        .time {
          font-size: $font-size-small;
        }
        .progress-bar-wrapper {
          width: 100%;
          margin: 0 16px;
        }
      }
      .operators {
        display: flex;
        justify-content: space-around;
        align-items: center;
        padding: 0 20px;
        .icon {
          color: $color-theme;
          font-size: 30px;
          &.i-center {
            font-size: 40px;
          }
        }
      }
      .dot-wrapper {
        display: flex;
        justify-content: center;
        .dot {
          width: 8px;
          height: 8px;
          margin: 0 4px;
          border-radius: 50%;
          background-color: $color-text-l;
          &.active {
            width: 20px;
            border-radius: 5px;
            background-color: $color-text-ll;
          }
        }
      }
    }
    &.normal-enter-active,
    &.normal-leave-active {
      transition: all 1s;
      .top,
      .middle,
      .bottom {
        transition: all 1s;
      }
    }
    &.normal-enter-from,
    &.normal-leave-to {
      opacity: 0;
      .top {
        transform: translate(-50%, -100%);
      }
      .middle {
        transform: translate(0, -100%);
      }
      .bottom {
        transform: translate(-50%, 100%);
      }
    }
  }
}
</style>
